package com.bub.pay.core.manager.user.impl;

import com.bub.pay.core.base.BaseManagerAbstract;
import com.bub.pay.core.base.IBaseManager;
import com.bub.pay.core.dao.SysUserDao;
import com.bub.pay.core.dao.SysUserRoleDao;
import com.bub.pay.core.entity.domain.SysUser;
import com.bub.pay.core.entity.domain.SysUserRole;
import com.bub.pay.core.entity.vo.user.*;
import com.bub.pay.core.manager.client.ClientManager;
import com.bub.pay.core.manager.system.CurrentSystemManager;
import com.bub.pay.core.manager.user.UserCommonManager;
import com.bub.pay.core.manager.user.UserManager;
import com.bub.pay.core.manager.user.role.UserRoleManager;
import com.bub.pay.core.util.SignUtil;
import com.bub.pay.framework.common.base.Cause;
import com.bub.pay.framework.common.entity.model.SessionModel;
import com.bub.pay.framework.common.entity.model.UserSession;
import com.bub.pay.framework.common.exception.GlobalException;
import com.bub.pay.framework.common.template.EmailTemplate;
import com.bub.pay.framework.common.util.*;
import com.bub.pay.framework.redis.RedisClient;
import com.bub.pay.framework.redis.model.EmailModel;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Service
public class UserManagerImpl extends BaseManagerAbstract<SysUser, SysUserDao>
        implements IBaseManager<SysUser>, UserManager {
    private ExecutorService executorService = Executors.newFixedThreadPool(20);

    @Resource
    private SysUserDao sysUserDao;

    @Resource
    private SysUserRoleDao sysUserRoleDao;

    @Resource
    private CurrentSystemManager currentSystemManager;

    @Resource
    private ClientManager clientManager;

    @Resource
    private UserCommonManager userCommonManager;

    @Resource
    private RedisClient redisClient;

    @Resource
    private UserRoleManager userRoleManager;


    @Override
    @Transactional
    public int addUser(AddSysUserVo vo) {
        String password = StrUtil.getSequence(8);
        SysUser newUser = new SysUser();
        BeanUtils.copyProperties(vo, newUser);
        newUser.setPassword(EncryptionUtil.encode().encode(DigestUtils.md5Hex(password)));
        newUser.setResetFlag(1);
        int i = sysUserDao.insertSelective(newUser);
        if (i == 0) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_add_user_fail);
        }
        for (Long roleId : vo.getRoleList()) {
            SysUserRole userRole = new SysUserRole();
            userRole.setRoleId(roleId);
            userRole.setUserId(newUser.getId());
            i = sysUserRoleDao.insertSelective(userRole);
            if (i == 0) {
                throw new GlobalException(currentSystemManager.getModule(), Cause.admin_add_user_role_fail);
            }
        }
        executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Map<String, String> data = new HashMap<>();
                String googleSecret = GoogleAuthenticator.generateSecretKey();
                data.put("username", vo.getUserName());
                data.put("password", password);
                data.put("googleSecret", googleSecret);
                EmailModel emailModel = new EmailModel();
                emailModel.setAddress(vo.getEmail());
                emailModel.setData(data);
                emailModel.setTemplateId(EmailTemplate.TEMPLATE_ADMIN_ADD_STAFF);
                clientManager.sendEmail(emailModel);
                return null;
            }
        });
        return i;
    }

    @Override
    public SysUser queryUser(Long extendId, int userType, int isSys) {
        if (extendId == null) {
            // 商户ID为空
            throw new GlobalException(currentSystemManager.getModule(), Cause.params_fail);
        }
        SysUser merchantUserCondition = new SysUser();
        merchantUserCondition.setExtendId(extendId);
        merchantUserCondition.setUserType(userType);
        merchantUserCondition.setIsSys(isSys);
        return sysUserDao.selectOne(merchantUserCondition);
    }

    @Override
    public String restPassword(Long id) {
        if (id == null) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.params_fail);
        }

        //  生成新的随机密码
        String password = RandomStringUtils.randomAlphanumeric(10);
        String passwordMd5 = DigestUtils.md5Hex(password);
        String passwordEncode = EncryptionUtil.encode().encode(passwordMd5);

        // 更新用户
        SysUser userUpdate = new SysUser();
        userUpdate.setId(id);
        userUpdate.setPassword(passwordEncode);
        userUpdate.setResetFlag(1);
        int updateCount = sysUserDao.updateByPrimaryKeySelective(userUpdate);
        if (updateCount != 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.unknown);
        }
        return password;
    }

    @Override
    public int restGoogleSecret(Long id) {
        return sysUserDao.restGoogleSecret(id);
    }

    @Override
    public Set<String> getAccessByUserName(String userName) {
        return sysUserDao.getAccessByUserName(userName);
    }

    @Override
    @Transactional
    public int updateUser(UpdateSysUserVo upUserVo) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(upUserVo, sysUser);
        sysUser.setId(upUserVo.getUserId());
        int i = sysUserDao.updateByPrimaryKeySelective(sysUser);
        if (i == 0) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_update_user_fail);
        }
        if (upUserVo.getRoleList() != null) {
            SysUserRole userRoleDel = new SysUserRole();
            userRoleDel.setDelFlag(true);
            Example userRoleExample = new Example(SysUserRole.class);
            userRoleExample.createCriteria().andEqualTo("userId", upUserVo.getUserId());
            sysUserRoleDao.updateByExampleSelective(userRoleDel, userRoleExample);

            upUserVo.getRoleList().forEach(e -> {
                SysUserRole userRoleAdd = new SysUserRole();
                userRoleAdd.setRoleId(e);
                userRoleAdd.setUserId(upUserVo.getUserId());
                int ii = sysUserRoleDao.insertSelective(userRoleAdd);
                if (ii == 0) {
                    throw new GlobalException(currentSystemManager.getModule(), Cause.admin_add_user_role_fail);
                }
            });
        }
        return i;
    }

    @Override
    public void restPayPassword(Long id) {
        sysUserDao.restPayPassword(id);
    }

    @Override
    public void updatePayPassword(UpdateUserPayPasswordVo updateUserPayPasswordVo) {
        // 校验
        UserSession userSession = ContextHolder.getUserSession();

        userCommonManager.checkGoogle(updateUserPayPasswordVo.getGoogleCode().toString());

        Example example = new Example(SysUser.class);
        example.createCriteria().andEqualTo("id", updateUserPayPasswordVo.getUserId())
                .andEqualTo("extendId", userSession.getExtendId())
                .andEqualTo("delFlag", false);
        SysUser user = sysUserDao.selectOneByExample(example);
        if (user == null) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_update_user_id_not_presence_err);
        }
        if (user.getIsSys() == 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.CanNotOperate);
        }

        // 修改
        SysUser updateUser = new SysUser();
        updateUser.setUserPayPass(EncryptionUtil.encode().encode(updateUserPayPasswordVo.getPayPassword().toLowerCase()));
        updateUser.setUpdateId(userSession.getUserId());
        updateUser.setUpdateDate(new Date());
        sysUserDao.updateByExampleSelective(updateUser, example);
    }

    @Override
    public void updatePassword(UpdateUserPasswordVo updateUserPasswordVo) {
        // 校验
        UserSession userSession = ContextHolder.getUserSession();

        userCommonManager.checkGoogle(updateUserPasswordVo.getGoogleCode().toString());

        Example example = new Example(SysUser.class);
        example.createCriteria().andEqualTo("id", updateUserPasswordVo.getUserId())
                .andEqualTo("extendId", userSession.getExtendId())
                .andEqualTo("delFlag", false);
        SysUser user = sysUserDao.selectOneByExample(example);
        if (user == null) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_update_user_id_not_presence_err);
        }
        if (user.getIsSys() == 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.CanNotOperate);
        }

        // 修改
        SysUser updateUser = new SysUser();
        updateUser.setPassword(EncryptionUtil.encode().encode(updateUserPasswordVo.getPassword().toLowerCase()));
        updateUser.setUpdateId(userSession.getUserId());
        updateUser.setUpdateDate(new Date());
        sysUserDao.updateByExampleSelective(updateUser, example);
    }

    @Override
    public void resetGoogleSecret(ResetUserGoogleSecretVo resetUserGoogleSecretVo) {
        // 校验
        UserSession userSession = ContextHolder.getUserSession();

        userCommonManager.checkGoogle(resetUserGoogleSecretVo.getGoogleCode().toString());

        Example example = new Example(SysUser.class);
        example.createCriteria().andEqualTo("id", resetUserGoogleSecretVo.getUserId())
                .andEqualTo("extendId", userSession.getExtendId())
                .andEqualTo("delFlag", false);
        SysUser user = sysUserDao.selectOneByExample(example);
        if (user == null) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_update_user_id_not_presence_err);
        }
        if (user.getIsSys() == 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.CanNotOperate);
        }

        // 修改
        sysUserDao.restGoogleSecret(resetUserGoogleSecretVo.getUserId());
    }

    @Override
    public void logoutUser(LogoutUserVo logoutUserVo) {
        // 校验
        UserSession userSession = ContextHolder.getUserSession();

        userCommonManager.checkGoogle(logoutUserVo.getGoogleCode().toString());

        Example example = new Example(SysUser.class);
        example.createCriteria().andEqualTo("id", logoutUserVo.getUserId())
                .andEqualTo("extendId", userSession.getExtendId())
                .andEqualTo("delFlag", false);
        SysUser user = sysUserDao.selectOneByExample(example);
        if (user == null) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.admin_update_user_id_not_presence_err);
        }
        if (user.getIsSys() == 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.CanNotOperate);
        }

        // 登出
        userCommonManager.deleteSession(logoutUserVo.getUserId().toString(), ContextHolder.getServletRequest());
    }

    @Override
    public Long queryUserExtendId(Long id, boolean cache) {
        if (!cache) {
            SysUser sysUser = getById(id);
            if (sysUser == null) {
                return null;
            }
            return sysUser.getExtendId();
        }

        String cacheKey = String.format("user:cache:extendId:%s", id);
        RedisTemplate<String, Object> redisTemplate = redisClient.getRedisTemplate();
        String extendId = (String) redisTemplate.opsForValue().get(cacheKey);
        if (StringUtils.isNotBlank(extendId)) {
            return Long.valueOf(extendId);
        }

        SysUser sysUser = getById(id);
        if (sysUser == null) {
            return null;
        }
        redisTemplate.opsForValue().set(cacheKey, sysUser.getExtendId().toString(), 1, TimeUnit.DAYS);
        return sysUser.getExtendId();
    }

    /**
     * @param updateSysUserVo 更新
     * @return 删除条数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteUser(UpdateSysUserVo updateSysUserVo) {
        Long userId = updateSysUserVo.getUserId();
        //用户角色表
        Example sysRoleExample = new Example(SysUserRole.class);
        Example.Criteria sysRoleExampleCriteria = sysRoleExample.createCriteria();
        sysRoleExampleCriteria.andEqualTo("userId", userId);
        List<SysUserRole> sysUserRoleList = userRoleManager.getByExample(sysRoleExample);
        if (!CollectionUtil.isNullOrEmpty(sysUserRoleList)) {
            sysUserRoleList.forEach((sysUserRole) -> {
                if (sysUserRole != null) {
                    if (sysUserRole.getUserId().equals(userId)) {
                        sysUserRole.setDelFlag(true);
                        sysUserRoleDao.updateByPrimaryKey(sysUserRole);
                    }
                }
            });
        }
        SysUser sysUser = getById(userId);
        sysUser.setDelFlag(true);
        int updateCount = sysUserDao.updateByPrimaryKeySelective(sysUser);
        if (updateCount != 1) {
            throw new GlobalException(currentSystemManager.getModule(), Cause.unknown);
        }
        return updateCount;
    }

    @Override
    public int resetPwdOrCode(ResetPwdOrCodeVo resetPwdOrCodeVo) {
        SysUser user = sysUserDao.selectByPrimaryKey(resetPwdOrCodeVo.getUserId());
        if (user == null) {
            throw new IllegalArgumentException("用户id不存在");
        }
        //发送邮件需要的参数
        String template = "";

        SessionModel sessionModel = ContextHolder.currentUserInfo();
        Long userId = sessionModel.getUserId();
        SysUser sysUser = new SysUser();
        String password = resetPWD();
        String googleSecret = resetGoogleSecretKey();
        String googleSecret1 = sessionModel.getGoogleSecret();
        String googleCode = resetPwdOrCodeVo.getGoogleCode();
        if (StringUtils.isBlank(googleCode)) {
            throw new IllegalArgumentException("谷歌验证码错误");
        }
        long verifyCode;
        try {
            verifyCode = Long.parseLong(googleCode);
        } catch (Exception e) {
            throw new IllegalArgumentException("谷歌验证码错误");
        }
        if (!GoogleAuthenticator.check_code(googleSecret1, verifyCode, System.currentTimeMillis())) {
            throw new IllegalArgumentException("谷歌验证码错误");
        }
        //重置登录密码
        if (resetPwdOrCodeVo.getType() == 1) {
            sysUser.setPassword(EncryptionUtil.encode().encode(password.toLowerCase()));
            template = EmailTemplate.TEMPLATE_RESET_MERCHANT_LOGIN_PASSWORD;
            //重置谷歌密钥
        } else if (resetPwdOrCodeVo.getType() == 2) {
            sysUser.setGoogleSecret(googleSecret);
            template = EmailTemplate.TEMPLATE_RESET_MERCHANT_GOOGLE_SECRET;
        } else {
            throw new IllegalArgumentException("错误的密码类型");
        }
        sysUser.setId(resetPwdOrCodeVo.getUserId());
        sysUser.setUpdateDate(new Date());
        sysUser.setUpdateId(userId);
        int i = sysUserDao.updateByPrimaryKeySelective(sysUser);
        if (i < 1) {
            throw new RuntimeException("重置失败");
        }
        //修改成功  发送邮件通知
        String finalTemplate = template;
        executorService.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Map<String, String> data = new HashMap<>();
                String googleSecret = GoogleAuthenticator.generateSecretKey();
                data.put("username", user.getUserName());
                data.put("password", password);
                data.put("googleSecret", googleSecret);
                EmailModel emailModel = new EmailModel();
                emailModel.setAddress(user.getEmail());
                emailModel.setData(data);
                emailModel.setTemplateId(finalTemplate);
                clientManager.sendEmail(emailModel);
                return null;
            }
        });
        return i;

    }

    private String resetPWD() {
        String newPWD = null;
        try {
            newPWD = SignUtil.sign("" + System.currentTimeMillis(), SignUtil.SIGN_WITH_MD5);
        } catch (Exception e) {
            throw new IllegalArgumentException("密码初始化失败");
        }
        return newPWD.substring(0, 16);
    }

    private String resetGoogleSecretKey() {
        return GoogleAuthenticator.generateSecretKey();
    }
}
